package com.citywithincity.db.drivers.mysql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.citywithincity.db.AbsSqlDriver;
import com.citywithincity.db.ColumnInfo;
import com.citywithincity.db.DbUtil;
import com.citywithincity.db.Entity;
import com.citywithincity.db.EntityField;
import com.citywithincity.db.SqlHelper;
import com.citywithincity.db.interfaces.IColumnDataValidate;
import com.citywithincity.db.interfaces.IValueConvert;
import com.citywithincity.db.interfaces.Select;
import com.citywithincity.db.validate.mysql.NumberValidate;

public class MysqlDriver extends AbsSqlDriver {
	
	public MysqlDriver() {
	}

	@Override
	public int insert(Connection connection,
			Object data,
			Entity<?> entity) throws SQLException{
		
		final EntityField[] fields = entity.getFields();
		final EntityField[] uniqueFields = entity.getUniqueFields();
		final String tableName = entity.getTableName();
		List<Object> insertValues = new ArrayList<Object>(fields.length);
		List<EntityField> insertFields = new ArrayList<EntityField>(fields.length);
		StringBuilder sb=SqlHelper.makeInsert(insertFields,insertValues, tableName, fields, uniqueFields, data);
		PreparedStatement ps = null;
		ResultSet rs = null;
		String sql = sb.toString();
		try{
			if(entity.isAuto()){
				ps = connection.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
				int result = SqlHelper.executeInsert(ps,sql,data,uniqueFields,insertFields,insertValues);
				if(result>0){
					Object value = getAutoIncrease(ps);
					entity.setAutoGenerate(data,value);
				}
				return result;
			}else{
				ps = connection.prepareStatement(sql);
				return SqlHelper.executeInsert(ps,sql,data,uniqueFields,insertFields,insertValues);
			}
		}finally{
			DbUtil.close(rs,ps);
		}
	}
	
	public void buildPage(StringBuilder sb, Integer position, Integer pageSize) {
		sb.append(" LIMIT ").append(position).append(',').append(pageSize);
	}

	public int posToPage(Integer position, Integer pageSize) {
		return position / pageSize + 1;
	}

	@Override
	public String protectTableName(String tableName) {

		return tableName;
	}

	@Override
	public PreparedStatement prepareInsert(Connection connection, String sql, String pk) throws SQLException {
		return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
	}

	@Override
	public Object getAutoIncrease(PreparedStatement ps) throws SQLException {
		ResultSet rs = null;
		try {
			rs = ps.getGeneratedKeys();
			if (rs.next()) {
				return rs.getLong(1);
			} else {
				return Long.valueOf(0);
			}
		} finally {
			DbUtil.close(rs);
		}
	}

	@Override
	public IColumnDataValidate createValidate(ColumnInfo columnInfo, ResultSetMetaData data) {
		if (columnInfo.clazz == Integer.class || columnInfo.clazz == Long.class) {
			// 检查是否是数字
			return new NumberValidate();
		}
		return null;
	}


	@Override
	public Class<?> getAutoIncreaseClass() {
		return Long.class;
	}


	@Override
	public Class<?> getColumnClass(ResultSetMetaData data, int i) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int insertOrUpdate(Select<?> ar, String tableName, String keyName, Map<String, Object> map) {
		StringBuilder sb = new StringBuilder();
		StringBuilder signs = new StringBuilder();
		sb.append("INSERT INTO ")
		.append(tableName)
		.append(" (");
		List<Object> values = new ArrayList<Object>();
		boolean first = true;
		for (Entry<String, Object> entry : map.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();
			if(first){
				first = false;
			}else{
				signs.append(',');
				sb.append(',');
			}
			sb.append(key);
			signs.append('?');
			values.add(value);
		}
		sb.append(") VALUES (").append(signs).append(") ON DUPLICATE KEY UPDATE ");
		first = true;
		for (Entry<String, Object> entry : map.entrySet()) {
			String key = entry.getKey();
			if(key.equals(keyName)){
				continue;
			}
			if(first){
				first = false;
			}else{
				sb.append(',');
			}
			sb.append(key).append("=?");
			values.add(entry.getValue());
		}
		return ar.executeUpdate(sb.toString(), values.toArray(new Object[values.size()]));
	}

	@Override
	public int insertOrUpdate(Select<?> ar, String tableName, String[] unikeys, Map<String, Object> map) {
		StringBuilder sb = new StringBuilder();
		StringBuilder signs = new StringBuilder();
		sb.append("INSERT INTO ")
		.append(tableName)
		.append(" (");
		List<Object> values = new ArrayList<Object>();
		boolean first = true;
		for (Entry<String, Object> entry : map.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();
			if(first){
				first = false;
			}else{
				signs.append(',');
				sb.append(',');
			}
			sb.append(key);
			signs.append('?');
			values.add(value);
		}
		sb.append(") VALUES (").append(signs).append(") ON DUPLICATE KEY UPDATE ");
		first = true;
		Set<String> keySet = new HashSet<String>();
		for (String string : unikeys) {
			keySet.add(string);
		}
		for (Entry<String, Object> entry : map.entrySet()) {
			String key = entry.getKey();
			if(keySet.contains(key)){
				continue;
			}
			if(first){
				first = false;
			}else{
				sb.append(',');
			}
			sb.append(key).append("=?");
			values.add(entry.getValue());
		}
		return ar.executeUpdate(sb.toString(), values.toArray(new Object[values.size()]));
	}

	@Override
	public IValueConvert create(Class<?> columnClass, Class<?> targetClass) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String protectColumn(String name) {
		
		return String.format("`%s`", name);
	}




}
